import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URL;
import java.text.Collator;
import java.util.ArrayList;
import java.util.Locale;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.Attributes;
import org.xml.sax.ErrorHandler;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.helpers.DefaultHandler;

public class SomatotypeIO
{
	public SomatotypeIO()
	{
		
	}
	public static void createCopy()
	{
		setSomatotypeList(getSomatotypeList(), nameFileCopy);
	}
	public static void deleteCopy()
	{
		File copy = new File(getSomatotypePath(nameFileCopy));
		if(copy.exists())
			try
			{
				copy.delete();
			}catch(SecurityException e)
			{
				Elite.addTextDebug(e.getMessage());
			}
	}
	public static void restoreFile()
	{
		File copy = new File(getSomatotypePath(nameFileCopy));
		if(!copy.exists())
			return;
		SomatotypeAthletes[] copyList = getSomatotypeList(nameFileCopy);
		setSomatotypeList(copyList);
	}
	public static void setSomatotypeList(SomatotypeAthletes[] sportSoma)
	{
		setSomatotypeList(sportSoma, nameFile);
	}
	private static void setSomatotypeList(SomatotypeAthletes[] sportSoma, String nameFile_)
	{
		try {
			 
			DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
			DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
	 
			// somatotype root element
			Document doc = docBuilder.newDocument();
			Element rootElement = doc.createElement("somatotype");
			doc.appendChild(rootElement);
			
			for(int i = 0; i < sportSoma.length; i++)
			{
				// sport elements
				Element sport = doc.createElement("sport");
				rootElement.appendChild(sport);
		 
				// name elements
				Element name = doc.createElement("name");
				name.appendChild(doc.createTextNode(sportSoma[i].getName()));
				sport.appendChild(name);
		 
				// male elements
				Element male = doc.createElement("male");
				sport.appendChild(male);
				
				// endo
				Element endoMale = doc.createElement("endo");
				endoMale.appendChild(doc.createTextNode(String.valueOf(sportSoma[i].getMaleSomatotype().getEndo())));
				male.appendChild(endoMale);
				
				// meso
				Element mesoMale = doc.createElement("meso");
				mesoMale.appendChild(doc.createTextNode(String.valueOf(sportSoma[i].getMaleSomatotype().getMeso())));
				male.appendChild(mesoMale);
							
				// ecto
				Element ectoMale = doc.createElement("ecto");
				ectoMale.appendChild(doc.createTextNode(String.valueOf(sportSoma[i].getMaleSomatotype().getEcto())));
				male.appendChild(ectoMale);
		 
				// female elements
				Element female = doc.createElement("female");
				sport.appendChild(female);
				
				// endo
				Element endoFemale = doc.createElement("endo");
				endoFemale.appendChild(doc.createTextNode(String.valueOf(sportSoma[i].getFemaleSomatotype().getEndo())));
				female.appendChild(endoFemale);
				
				// meso
				Element mesoFemale = doc.createElement("meso");
				mesoFemale.appendChild(doc.createTextNode(String.valueOf(sportSoma[i].getFemaleSomatotype().getMeso())));
				female.appendChild(mesoFemale);
							
				// ecto
				Element ectoFemale = doc.createElement("ecto");
				ectoFemale.appendChild(doc.createTextNode(String.valueOf(sportSoma[i].getFemaleSomatotype().getEcto())));
				female.appendChild(ectoFemale);
			}
			// write the content into xml file
			TransformerFactory transformerFactory = TransformerFactory.newInstance();
			Transformer transformer = transformerFactory.newTransformer();
			transformer.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM,"somatotype.dtd");
			transformer.setOutputProperty(OutputKeys.INDENT,"yes");
			DOMSource source = new DOMSource(doc);
			File file = new File(getSomatotypePath(nameFile_));
			if(!file.exists())
				file.createNewFile();
			StreamResult result = new StreamResult(new FileOutputStream(file));
	 
			// Output to console for testing
			// StreamResult result = new StreamResult(System.out);
	 
			transformer.transform(source, result);			
	 
		} 
		catch (ParserConfigurationException pce) 
		{
			Elite.addTextDebug(pce.getMessage());
		}
		catch(IOException ioe)
		{
			Elite.addTextDebug(ioe.getMessage());
		}
		/*catch (FileNotFoundException fnfe)
		{
			Elite.addTextDebug(fnfe.getMessage());
		}*/
		catch (TransformerException tfe) 
		{
			Elite.addTextDebug(tfe.getMessage());
		} 
	}
	public static SomatotypeAthletes[] getSomatotypeList()
	{
		return getSomatotypeList(nameFile);
	}
	private static SomatotypeAthletes[] getSomatotypeList(String nameFile_)
	{
		ArrayList<String> sportList = SomatotypeIO.getSportsList(nameFile_);
		SomatotypeAthletes[] sportSoma = new SomatotypeAthletes[sportList.size()];
		for(int i = 0; i < sportList.size(); i++)
		{
			SomatotypeAthletes aux = new SomatotypeAthletes();
			aux.setName(sportList.get(i));
			aux.setMaleSoma(SomatotypeIO.getSomatotype(aux.getName(), PersonalData.MALE));
			aux.setFemaleSoma(SomatotypeIO.getSomatotype(aux.getName(), PersonalData.FEMALE));
			sportSoma[i] = aux;
		}
		return sportSoma;
	}
	public static Somatotype getSomatotype(String sportID,String gender)
    {
        /*ResourceBundle somatotype = 
            ResourceBundle.getBundle("somatotype.somatotype_"+gender);
        return new Somatotype(
            new Double(somatotype.getString(sportID+"_endo")),
            new Double(somatotype.getString(sportID+"_meso")),
            new Double(somatotype.getString(sportID+"_ecto"))
        );*/
    	try
    	{
    		//InputStream sequence = SomatotypeAthletes.class.getResourceAsStream(urlSomatotype);
    		//URL url = SomatotypeAthletes.class.getResource(urlSomatotype);
    		DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
    		dbFactory.setValidating(true);
    		DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
    		dBuilder.setErrorHandler(new 
				ErrorHandler()
				{
					public void warning(SAXParseException exception)throws SAXException 
					{
						exception.printStackTrace();
					}
					public void error(SAXParseException exception)throws SAXException 
					{
						exception.printStackTrace();
					}
					public void fatalError(SAXParseException exception)throws SAXException 
					{
						exception.printStackTrace();
					}
				}
    		);
    		Document doc = dBuilder.parse(new File(getSomatotypePath(nameFile)));//url.toURI()));
    		doc.getDocumentElement().normalize();
    		
    		NodeList nList = doc.getElementsByTagName("sport");
    		for (int i = 0; i < nList.getLength(); i++) 
    		{
    			Node nNode = nList.item(i);
    			if (nNode.getNodeType() == Node.ELEMENT_NODE) 
    			{
    				Element eElement = (Element) nNode;
    				if(getTagValue("name", eElement).equals(sportID))
    				{
    					return getSoma(gender,eElement);
    				}
    			}
    		}
    	}catch(Exception e)
    	{
    		e.printStackTrace();
    		Elite.addTextDebug(e.getMessage());
    	}
    	return new Somatotype();
    }
	public static ArrayList<String> getSportsList()
	{
		return getSportsList(nameFile);
	}
    private static ArrayList<String> getSportsList(String nameFile_)
    {
        try 
        {
        	SomatotypeHandler handler = new SomatotypeHandler();
        	SAXParserFactory factory = SAXParserFactory.newInstance();
        	factory.setValidating(true);
        	SAXParser saxParser = factory.newSAXParser();
        	//InputStream sequence = SomatotypeAthletes.class.getResourceAsStream(urlSomatotype);
        	//URL url = SomatotypeAthletes.class.getResource("Elite.java");
        	//File file_aux = new File(url.toURI());
        	//Elite.addTextDebug("URI: "+file_aux.getParentFile()+urlSomatotype);
	        saxParser.parse(getSomatotypePath(nameFile_), handler);
	        return  handler.getList();
        } catch (Exception e) 
        {
        	//e.printStackTrace();
        	Elite.addTextDebug(e.getMessage());
        	ArrayList<String> aux = new ArrayList<String>(1);
        	aux.add("");
        	return  aux;
        }
    }
    private static String getTagValue(String sTag, Element eElement) 
    {
		NodeList nlList = eElement.getElementsByTagName(sTag).item(0).getChildNodes();
		Node nValue = (Node) nlList.item(0);
		return nValue.getNodeValue().trim();
    }
    private static Somatotype getSoma(String sTag, Element eElement) 
    {
    	Somatotype soma = new Somatotype(); 
    	NodeList nlList = eElement.getElementsByTagName(sTag);
    	eElement = (Element) nlList.item(0);
		
		soma.setEndo(new Float(getTagValue("endo", eElement)));
		soma.setMeso(new Float(getTagValue("meso", eElement)));
		soma.setEcto(new Float(getTagValue("ecto", eElement)));
		return soma;
    }
    private static String getSomatotypePath(String name)
    {
    	if(name.equals(nameFile))
    		return getSomatotypePath();
    	else if(name.equals(nameFileCopy))
    		return getSomatotypeCopyPath();
    	else
    		return null;
    }
    private static String getSomatotypePath()
    {
    	String urlSomatotype = File.separatorChar+nameFolder+File.separatorChar+nameFile;
    	URL url = SomatotypeAthletes.class.getResource("Elite.java");
    	File fileSomatotype;
    	try
    	{
    		File file_aux = new File(url.toURI());
    		fileSomatotype = new File(file_aux.getParentFile(),urlSomatotype);
    		if(fileSomatotype.exists())
    			return file_aux.getParent()+urlSomatotype;
    	}
    	catch(Exception e)
    	{
    		Elite.addTextDebug(e.getMessage());
    	}
		fileSomatotype = new File(System.getProperty("user.dir"),"elite"+urlSomatotype);
		Elite.addTextDebug("URI: "+System.getProperty("user.dir")+"elite"+urlSomatotype);
		if(fileSomatotype.exists())
			return System.getProperty("user.dir")+File.separatorChar+"elite"+urlSomatotype;
		fileSomatotype = new File(System.getProperty("user.dir"),urlSomatotype);
		Elite.addTextDebug("URI: "+System.getProperty("user.dir")+urlSomatotype);
		if(fileSomatotype.exists())
			return System.getProperty("user.dir")+File.separatorChar+urlSomatotype;
		else
			return null;
    		
    }
    private static String getSomatotypeCopyPath()
    {
    	String filePath = getSomatotypePath();
    	File path = new File(filePath);
    	return path.getParent()+File.separatorChar+nameFileCopy;
    }
    private static class SomatotypeHandler extends DefaultHandler
    {
    	public SomatotypeHandler()
    	{
    		sportsList = new ArrayList<String> (15);
    		//sportsList.add("");
    	}
    	public void startElement(String uri, String localName,String qName, Attributes attributes) throws SAXException 
        {
    		if (qName.equalsIgnoreCase("name"))
    			name = true;
        }
    	public void endElement(String uri, String localName, String qName) throws SAXException 
    	{
			
		}
    	public void characters(char ch[], int start, int length) throws SAXException 
    	{
    		if(name)
    		{
    			String aux = new String(ch,start,length);
    			sportsList.add(aux.trim());
    			name = false;
    		}
    	}
    	public ArrayList<String> getList()
    	{
    		if((sportsList.size() == 0)||(sportsList.size() == 1))
    			return sportsList;
    		Collator collator = Collator.getInstance(Resources.getLocale());
    		collator.setStrength(Collator.PRIMARY);
    		for( int i = 1 , j= 0; i < sportsList.size(); i++)
    		{
    			String aux = sportsList.get(i);
				j = i-1;
    			while(collator.compare(aux, sportsList.get(j)) < 0)//aux.toLowerCase().compareTo(sportsList.get(j).toLowerCase()) < 0)
    			{
    				sportsList.remove(aux);
    				sportsList.add(j,aux);
    				if(j-1 >= 0)
    					j--;
    				else 
    					break;
    			}
    		}
    		return sportsList;
    	}
    	private boolean name;
    	private ArrayList <String> sportsList;
    }
    private static String nameFolder = "somatotype";
    private static String nameFileCopy = "somatotype.xml~";//File.separatorChar+"somatotype"+File.separatorChar+"somatotype.xml~";
    private static String nameFile = "somatotype.xml";//File.separatorChar+"somatotype"+File.separatorChar+"somatotype.xml";
}